﻿using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;

namespace Xms.Abp.Caching;

public class GeoCache : IGeoCache
{
    protected IAbpLazyServiceProvider LazyServiceProvider { get; }

    public bool MultiTenancyIsEnable { get; set; } = true;

    protected ICacheProvider CacheProvider { get; }
    protected IXmsCache _cache;
    protected IXmsCache Cache
    {
        get
        {
            if (_cache == null)
            {
                _cache = CacheProvider.GetCache();
            }
            return _cache;
        }
    }

    protected IDistributedCacheKeyNormalizer KeyNormalizer => LazyInject<IDistributedCacheKeyNormalizer>();

    protected string CacheKey { get; set; }
    protected string CacheName { get; set; }

    public GeoCache(
        IAbpLazyServiceProvider lazyServiceProvider,
        ICacheProvider cacheProvider,
        string cacheName = null)
    {
        LazyServiceProvider = lazyServiceProvider;
        CacheProvider = cacheProvider;
        MultiTenancyIsEnable = true;

        CacheName = cacheName;

        CacheKey = LazyInject<IDistributedCacheKeyNormalizer>()
            .NormalizeKey(new DistributedCacheKeyNormalizeArgs(null, CacheName, !MultiTenancyIsEnable));
    }

    public TService LazyInject<TService>()
    {
        return LazyServiceProvider.LazyGetRequiredService<TService>();
    }

    public Task<double?> DistanceAsync(string member1, string member2, CancellationToken cancellationToken = default)
    {
        return Cache.GeoDistanceAsync(CacheKey, member1, member2, cancellationToken);
    }

    public Task<GeoRadiusItem[]> RadiusAsync(string member, double radius, CancellationToken cancellationToken = default)
    {
        return Cache.GeoRadiusAsync(CacheKey, member, radius, cancellationToken);
    }

    public Task<GeoRadiusItem[]> RadiusAsync(double longitude, double latitude, double radius, CancellationToken cancellationToken = default)
    {
        return Cache.GeoRadiusAsync(CacheKey, longitude, latitude, radius, cancellationToken);
    }

    public Task<GeoPositionItem> GetAsync(string member, CancellationToken cancellationToken = default)
    {
        return Cache.GetGeoAsync(CacheKey, member, cancellationToken);
    }

    public Task<IEnumerable<KeyValuePair<string, GeoPositionItem>>> GetManyAsync(string[] members, CancellationToken cancellationToken = default)
    {
        return Cache.GetGeoManyAsync(CacheKey, members, cancellationToken);
    }

    public Task<IEnumerable<KeyValuePair<string, GeoPositionItem>>> GetManyAsync(IEnumerable<string> members, CancellationToken cancellationToken = default)
    {
        return Cache.GetGeoManyAsync(CacheKey, members, cancellationToken);
    }

    public Task<bool> KeyExistsAsync(CancellationToken cancellationToken = default)
    {
        return Cache.KeyExistsAsync(CacheKey, cancellationToken);
    }

    public Task RemoveAsync(CancellationToken cancellationToken = default)
    {
        return Cache.RemoveAsync(CacheKey, cancellationToken);
    }

    public Task<bool> RemoveAsync(string member, CancellationToken cancellationToken = default)
    {
        return Cache.RemoveGeoAsync(CacheKey, member, cancellationToken);
    }

    public Task SetAsync(string member, double longitude, double latitude, CancellationToken cancellationToken = default)
    {
        return Cache.SetGeoAsync(CacheKey, member, longitude, latitude, cancellationToken);
    }

    public Task SetAsync(string member, GeoPositionItem position, CancellationToken cancellationToken = default)
    {
        return Cache.SetGeoAsync(CacheKey, member, position, cancellationToken);
    }

    public Task SetManyAsync(IEnumerable<KeyValuePair<string, GeoPositionItem>> geos, CancellationToken cancellationToken = default)
    {
        return Cache.SetGeoManyAsync(CacheKey, geos, cancellationToken);
    }
}
